/*
 * CFileUploadClient.cpp
 *
 *  Created on: 2017年11月8日
 *      Author: zhengboyuan
 */

#include "CFileUploadClient.h"

static void ev_handler(struct mg_connection *nc, int ev, void *ev_data)
{
	CFileUploadClient* client = (CFileUploadClient*)(nc->mgr->user_data);
	client->handleEvent(nc, ev, ev_data);
}


CFileUploadClient::CFileUploadClient():
		m_task(),
		m_sink(),
		m_mgr(),
		m_connection()
{
	mg_mgr_init(&m_mgr, NULL);
	m_mgr.user_data = this;
}

CFileUploadClient::~CFileUploadClient()
{
	close();
}

bool CFileUploadClient::upload(const std::string& url, const StringMap& headers, const StringMap& formData, const FileUploadArray& files)
{
	fireStatus(kUploadBegin, "");

	m_stream.addFormData(formData);

	for (size_t i = 0; i < files.size(); ++i)
	{
		const FileUpload& fileUpload = files[i];
		m_stream.addFile(fileUpload.name, fileUpload.mime, fileUpload.filepath);
	}

	std::string contentType = "content-type: multipart/form-data; boundary=";
	contentType += m_stream.boundary();

	std::string extra_headers;

	extra_headers += contentType;
	extra_headers += "\r\n";

	for (StringMap::const_iterator it = headers.begin(); it != headers.end(); ++it)
	{
		extra_headers += it->first;
		extra_headers += ": ";
		extra_headers += it->second;
		extra_headers += "\r\n";
	}

	int length = m_stream.getLength();

	m_connection = mg_connect_http3(&m_mgr, ev_handler, url.c_str(),
		extra_headers.c_str(), length);

	int size = m_stream.read(m_buffer, BUFFER_SIZE);
	if (size > 0)
	{
		mg_send(m_connection, m_buffer, size);
	}

	start();

	return m_connection != NULL;
}

void CFileUploadClient::close()
{
	if (isRunning())
	{
		stop();
	}
}

void CFileUploadClient::cancel()
{
	close();
}

void CFileUploadClient::setSink(Sink* sink)
{
	m_sink = sink;
}

const std::string& CFileUploadClient::getUrl()
{
	return m_task.url;
}

int CFileUploadClient::getId()
{
	return m_task.id;
}

void CFileUploadClient::setId(int id)
{
	m_task.id = id;
}

int CFileUploadClient::run()
{
	while (!m_canExit)
	{
		mg_mgr_poll(&m_mgr, 1000);
	}
	return 0;
}

void CFileUploadClient::doStop()
{
	//
}


void CFileUploadClient::handleEvent(struct mg_connection *nc, int ev, void *ev_data)
{
	struct http_message *hm = (struct http_message *) ev_data;
	//printf("CFileUploadClient::handleEvent. ev:%d\n", ev);

	switch (ev)
	{
		case MG_EV_CONNECT:
		{
			int code = *((int *)ev_data);
			if (code == 0)
			{
				fireStatus(kUploadConnected, std::string());
			}
			else
			{
				const char* text = strerror(code);
				std::string result(text, strlen(text));
				fireStatus(kUploadError, result);
			}
			break;
		}
		case MG_EV_RECV:
		{
			int num_bytes = *((int*)ev_data);
			//m_recvBytes += num_bytes;
			//printf("recv. total:%d, len:%d\n", m_recvBytes, num_bytes);
			break;
		}
		case MG_EV_HTTP_REPLY:
		{
			nc->flags |= MG_F_CLOSE_IMMEDIATELY;
			std::string result(hm->body.p, hm->body.len);
			fireStatus(kUploadEnd, result);
			break;
		}
		case MG_EV_SEND:
		{
			int num_bytes = *((int*)ev_data);
			//printf("send. len:%d\n", num_bytes);

			int size = m_stream.read(m_buffer, BUFFER_SIZE);
			if (size > 0)
			{
				mg_send(m_connection, m_buffer, size);
			}
			else
			{
				//printf("send all.\n");
			}

			break;
		}
		default:
		{
			break;
		}
	}
}

void CFileUploadClient::fireStatus(int status, const std::string& result)
{
	if (m_sink)
	{
		m_sink->onFileUploadStatus(this, status, result);
	}
}

void CFileUploadClient::fireProgress()
{

}